<template>
  <div class="Learning-pulsatingAudio">
    <codeContainer>
      <template #default>
        <div class="canvas-wrapper" ref="canvasWrapper">
          <canvas ref="canvas"></canvas>
        </div>
        <div class="audio-wrapper">
          <input type="file" @change="handleSubmit"/>
          <audio :src="mp3" controls ref="audio"></audio>
        </div>
      </template>
      <template #code>
            <pre data-type="js">
              {{ codeFragment["pulsatingAudio-1"] }}
            </pre>
      </template>
    </codeContainer>
  </div>
</template>

<script setup>
import {
  onMounted, onUnmounted, ref
} from 'vue';
import { useEventListener } from '@/assets/js/hooks';
import CodeContainer from '@/components/codeContainer/codeContainer.vue';
import codeFragment from '../../assets/js/codeFragment';
import music from './mp3/Believer.mp3';
// codeFragment-split
const mp3 = ref(music);
const audio = ref(null);
const canvas = ref(null);
let canvasTop;
const canvasWrapper = ref(null);
let dataArray;
let analyser;
// 获取主题颜色
const fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--learning-color-1');
let ctx;
let isInit = false;
let isDraw = false;
let isScroll = false;
let timer;

function handleSubmit(e) {
  const [ file ] = e.target.files;
  if (!file) return;
  const { type } = file;
  if (!type.includes('audio')) {
    // eslint-disable-next-line no-alert
    alert('仅支持音频格式文件！');
    return;
  }
  mp3.value = URL.createObjectURL(file);
}

function setCanvasSize() {
  canvas.value.width = canvasWrapper.value.clientWidth;
  canvas.value.height = canvasWrapper.value.clientHeight;
}

// 把分析的波形绘制到canvas上
function draw() {
  if (!isDraw || isScroll) return;
  setCanvasSize();
  // 动画帧 每帧调用一次绘制方法
  requestAnimationFrame(draw);
  const { width, height } = canvas.value;
  // 清空画布
  ctx.clearRect(0, 0, width, height);
  ctx.fillStyle = fillStyle;
  if (!isInit) return;

  // 分析结果塞入到数组中
  analyser.getByteFrequencyData(dataArray);
  // 长度应为fftSize的一半
  const len = dataArray.length / 2;
  // 柱子宽度
  const barWidth = width / len;
  for (let i = 0; i < len; i += 1) {
    const data = dataArray[i];
    // 柱子高度
    const barHeight = (data / 256) * height;
    // 右半边绘制起点
    const x1 = i * barWidth + width / 2;
    // 左半边绘制起点
    const x2 = (width / 2) - (i + 1) * barWidth;
    const y = height - barHeight;
    ctx.fillRect(x1, y, barWidth - (barWidth / 10), barHeight);
    ctx.fillRect(x2, y, barWidth - (barWidth / 10), barHeight);
  }
}

onMounted(() => {
  canvasTop = canvas.value.getBoundingClientRect().top;
  audio.value.volume = 0.1;
  audio.value.focus();
  // 设置canvas宽高
  setCanvasSize();
  // 创建2d画布
  ctx = canvas.value.getContext('2d');
  ctx.fillStyle = fillStyle;

  audio.value.onplay = () => {
    if (timer) clearTimeout(timer);
    if (isInit) {
      isDraw = true;
      draw();
    } else {
      // 创建一个音频上下文
      const audCtx = new AudioContext();
      // 创建音频源节点
      const source = audCtx.createMediaElementSource(audio.value);
      // 创建音频分析器
      analyser = audCtx.createAnalyser();
      analyser.fftSize = 128;
      // 创建一个长度为 analyser.fftSize 一半长度的Uint8Array
      dataArray = new Uint8Array(analyser.frequencyBinCount);
      // 链接到分析器
      source.connect(analyser);
      // 链接到输出设备
      analyser.connect(audCtx.destination);
      isDraw = true;
      draw();
      isInit = true;
    }
  };

  audio.value.onpause = () => {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      isDraw = false;
    }, 1000);
  };
});
let scrollTimer;

function handleScroll() {
  isScroll = true;
  if (scrollTimer) clearTimeout(scrollTimer);
  scrollTimer = setTimeout(() => {
    const Rect = canvas.value.getBoundingClientRect();
    if (canvasTop - Rect.top < Rect.height + canvasTop - 40) {
      isScroll = false;
      draw();
    }
  }, 200);
}

useEventListener(window, 'scroll', handleScroll);
onUnmounted(() => {
  isDraw = false;
});
</script>

<style scoped lang="scss">
.Learning-pulsatingAudio {
  .canvas-wrapper {
    border: 1px solid var(--learning-border-color);
    //height: 400px;
    height: 0;
    width: 100%;
    padding-bottom: 50%;
  }

  .audio-wrapper {
    display: flex;
    align-items: center;
    height: 100px;

    audio {
      outline: 0;
    }
  }
}
</style>
